//
//  AEControl.cpp
//  GameJam-Mac
//
//  Created by Clover Sin on 12/26/11.
//  Copyright (c) 2011 Snow Poem Society. All rights reserved.
//

#include "stdafx.h"

#include "AEControl.h"

AEControl::AEControl(AEControl* parent, AETheme* theme): 
    _parentControl(parent), 
    _theme(theme), 
    _visible(true), 
    _enable(true), 
    _active(false), 
    _state(CS_Normal), 
    _timer(0.0f), 
    _countingTimer(false), 
    _mouseDownButton(MOUSE_BUTTON_NONE), 
    _occupyCursor(true), 
    _offsetFromParent(Vector2::Zero)
{
    // Set up layer for rendering. 
    if (_parentControl)
    {
        // Child controls are always on top of parents. 
        _layerNumber = _parentControl->getLayerNumber() + 1;
    }
    
    // Set default position to centroid of parent.
    if (_parentControl)
        this->SetPosition(_parentControl->GetPosition());
    else
        this->SetPosition(Vector2::Zero);
    
    // Add self to parent. 
    if (_parentControl)
    {
        _parentControl->_childControls.push_back(this);
    }
}

bool AEControl::isVisible()
{
    return _visible;
}

void AEControl::setVisible(bool flag)
{
    _visible = flag;
    
    for (ChildControlIt it = _childControls.begin(); 
         it != _childControls.end(); 
         ++it)
    {
        (*it)->setVisible(flag);
    }
}

bool AEControl::isEnable()
{
    return _enable;
}

void AEControl::setEnable(bool flag)
{
    _enable = flag;
    
    for (ChildControlIt it = _childControls.begin(); 
         it != _childControls.end(); 
         ++it)
    {
        (*it)->setEnable(flag);
    }
}

bool AEControl::isActive()
{
    return _active;
}

void AEControl::setOffsetFromParent(const Vector2& offset)
{
    _offsetFromParent = offset;
}

Vector2 AEControl::getOffsetFromParent()
{
    return _offsetFromParent;
}

void AEControl::setControlPosition(const Vector2 &new_pos)
{
    this->SetPosition(new_pos);
    
    syncChildrenPosition();
}

bool AEControl::containsPointAt(const Vector2 &pos)
{
    return this->getCollisionBox().Contains(pos);
}

bool AEControl::containsPointAt(float x, float y)
{
    return this->containsPointAt(Vector2(x, y));
}

bool AEControl::containsPointAt(const Vec2i &pos)
{
    return this->containsPointAt(Vector2(pos.X, pos.Y));
}

AEControl* AEControl::getControlAt(const Vector2 &pos)
{
    AEControl* result = NULL;
    
    // Check if there's a child at that point.
    for (ChildControlIt it = _childControls.begin(); 
         it != _childControls.end(); 
         ++it)
    {
        if ((*it)->isVisible() && (*it)->isOccupyingCursor()) 
        {
            if ((*it)->containsPointAt(pos))
                result = (*it)->getControlAt(pos);
        }
    }
    
    // If no child there, check if self contains that point.
    if (!result)
    {
        if (this->containsPointAt(pos))
        {
            result = this;
        }
    }
    
    return result;
}

AEControl* AEControl::getControlAt(float x, float y)
{
    return this->getControlAt(Vector2(x, y));
}

AEControl* AEControl::getControlAt(const Vec2i &pos)
{
    return this->getControlAt(Vector2(pos.X, pos.Y));
}

AEControl* AEControl::getParentControl()
{
    return _parentControl;
}

void AEControl::setDelegate(AEDelegate delegate)
{
    _delegate = delegate;
}

void AEControl::Update(float dt)
{
    // _Update() should be added if you reimplement
    //   the Update() method. 
    _Update(dt);
}

BoundingBox AEControl::getCollisionBox()
{
    Vector2 min = this->GetPosition() - this->GetSize() / 2.0f;
    Vector2 max = this->GetPosition() + this->GetSize() / 2.0f;
    
    return BoundingBox(min, max);
}

int AEControl::getLayerNumber()
{
    return _layerNumber;
}

void AEControl::syncChildrenPosition()
{
    for (ChildControlIt it = _childControls.begin();
         it != _childControls.end();
         ++it)
    {
        (*it)->setControlPosition(this->GetPosition() + (*it)->_offsetFromParent);
    }
}

bool AEControl::_MouseDown(Vector2 coor, MouseButtonInput button)
{    
    // Check if it is root, if it is root, 
    //   eat current event(return true).
    // TODO: Allow some events which can be 
    //   handled by the root or manager.
    if (! this->_parentControl)
    {
        return true;
    }
    
    if (! this->MouseDown(coor, button))
    {
        return _parentControl->_MouseDown(coor, button);
    }
    
    // Change state. 
    _state = CS_PressDown;
    
    // Store button for telling left-click or right-click
    _mouseDownButton = button;
    
    // Start counting time, to catch a click event. 
    _countingTimer = true;
    
    return true;
}

bool AEControl::_MouseUp(Vector2 coor, MouseButtonInput button)
{
    // Check if it is root, if it is root, 
    //   eat current event(return true).
    // TODO: Allow some events which can be 
    //   handled by the root or manager.
    if (! this->_parentControl)
    {
        return true;
    }
    
    if (! this->MouseUp(coor, button))
    {
        return _parentControl->_MouseUp(coor, button);
    }
    
    _state = CS_Normal;
    
    if (button == _mouseDownButton)
    {
        if (_countingTimer)
        {
            // Check if it is a click event. 
            if (_timer < CLICK_DURATION)
            {
                MouseClick(button);
            }
            
            // Check if mouse is still hover the button. 
            if (containsPointAt(coor))
            {
                _state = CS_MouseHover;
                MouseHover(coor);
            }
        }
    }
    
    // Reset variables. 
    _timer = 0.0f;
    _countingTimer = false;
    _mouseDownButton = MOUSE_BUTTON_NONE;
    
    return true;
}

void AEControl::_Update(float dt)
{    
    if (_countingTimer)
    {
        _timer += dt;
    }
}

bool AEControl::_MouseMotion(Vector2 coor)
{
    // Check if it is root, if it is root, 
    //   eat current event(return true).
    // TODO: Allow some events which can be 
    //   handled by the root or manager.
    if (! this->_parentControl)
    {
        return true;
    }
    
    if (! this->MouseMotion(coor))
    {
        return _parentControl->_MouseMotion(coor);
    }
    
    return true;
}

bool AEControl::_MouseEnter(Vector2 coor)
{
    // Check if it is root, if it is root, 
    //   eat current event(return true).
    // TODO: Allow some events which can be 
    //   handled by the root or manager.
    if (! this->_parentControl)
    {
        return true;
    }
    
    if (! this->MouseEnter(coor))
    {
        return _parentControl->_MouseEnter(coor);
    }
    
    return true;
}

bool AEControl::_MouseLeave(Vector2 coor)
{
    // Check if it is root, if it is root, 
    //   eat current event(return true).
    // TODO: Allow some events which can be 
    //   handled by the root or manager.
    if (! this->_parentControl)
    {
        return true;
    }
    
    if (! this->MouseLeave(coor))
    {
        return _parentControl->_MouseLeave(coor);
    }
    
    return true;
}

bool AEControl::_MouseHover(Vector2 coor)
{
    // Check if it is root, if it is root, 
    //   eat current event(return true).
    // TODO: Allow some events which can be 
    //   handled by the root or manager.
    if (! this->_parentControl)
    {
        return true;
    }
    
    if (! this->MouseHover(coor))
    {
        return _parentControl->MouseHover(coor);
    }
    
    return true;
}

